package com.wangdong.wdbase.exception;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.os.Looper;
import android.os.SystemClock;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;


import com.wangdong.wdbase.base.XTActivityStack;
import com.wangdong.wdutils.utils.DLDateUtils;
import com.wangdong.wdutils.utils.DLPreferencesUtil;
import com.wangdong.wdutils.utils.DLSystemUtil;

import org.json.JSONObject;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 异常处理类
 *
 *      逻辑说明:
 *      就是通过继承全局异常接口UncaughtExceptionHandler
 *      初始化
 *      Thread.setDefaultUncaughtExceptionHandler(this);// 设置该ExceptionHandler该类为程序的默认处理器
 *      如果发生没有捕获异常
 *              会在当UncaughtException发生时会转入该函数来处理
 *              然后把异常写到本地sd存储
 *              在然后把存储好的.txt文件通过网络上传给服务器
 *
 *              如果:要在给其他app使用注意用户名字获取,和保存文件命名和路径命名
 *
 * @author zhou
 */
public class ExceptionHandler implements UncaughtExceptionHandler//线程未捕获异常处理器，用来处理未捕获异常
       {

    private static final String TAG = ExceptionHandler.class.getSimpleName();

    /**
     * 本类实例
     **/
    private static ExceptionHandler instance;

    /**
     * 程序的Context对象
     */
    private Context mContext;


    /**
     * 私有化构造方法
     **/
    private ExceptionHandler() {
    }

    /**
     * 获取本类实例
     *
     * @return
     */
    public synchronized static ExceptionHandler getInstance() {
        if (instance == null) {
            instance = new ExceptionHandler();
        }
        return instance;
    }

    /**
     * 初始化
     */
    public void init(Context context) {
        mContext = context;
        Thread.setDefaultUncaughtExceptionHandler(this);// 设置该ExceptionHandler该类为程序的默认处理器

    }

    /**
     * 当UncaughtException发生时会转入该函数来处理
     */
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        if (ex == null) {
            // 异常信息为null,那么也就不需要我们做上传日志操作了，直接关闭应用
            closeApplication(3000);
        } else {
            // 如果异常信息不为null，那么我们便需要将异常信息保存到本地文件上,便于我们以后做上传收集异常信息
            handleException(ex);
        }
    }

    /**
     * 异常处理
     *
     * @param e 异常信息
     */
    public void handleException(Throwable e) {

        Log.e(TAG, "<----------- Exception start --------->");
        e.printStackTrace();
        Throwable cause = e.getCause();
        if (cause != null) {
            cause.printStackTrace();
        }
        Log.e(TAG, "<----------- Exception end  --------->");

        if (existSDCard()) {//判断sd卡是否存在
            // 如果用户有sdcard,那么我们将异常信息保存为一个文件至sdcard,如果没有sdcard就算了。
            saveToFile(e);//保存SD卡
        }
        closeApplication(3000);//延迟3秒后关闭app
    }

    /**
     * 按照json格式保存到文件中
     *
     * @param e
     */
    protected void saveJsonToFile(Throwable e) {

        try {
            JSONObject content = new JSONObject();
            // 系统
            content.put("os", "android");
            // 用户名
            // content.put("userCode", mUserName);
            // 信息
            content.put("msg", e.toString());
            // 1.处理类
            content.put("className", ExceptionHandler.class.getName());
            // 2.时间
            long time = System.currentTimeMillis();
            String date = DLDateUtils.dateToStr(new Date(time));
            content.put("date", date);
            // 3.设备imei号
            content.put("imei", getIMEI(mContext));
            // 4.当前应用版本
            content.put("version", getAppVersion(mContext));
            // 5.堆栈信息
            StringBuilder sb = new StringBuilder();
            StackTraceElement[] stackTrace = e.getStackTrace();
            for (int i = 0; i < stackTrace.length; i++) {
                String line = i + "-->" + stackTrace[i].toString()
                        + System.getProperty("line.separator");
                sb.append(line);
            }
            content.put("stack", sb.toString());

            // 6.CauseBy
            Throwable cause = e.getCause();
            if (cause != null) {
                StringBuilder sb1 = new StringBuilder();
                StackTraceElement[] trace1 = cause.getStackTrace();
                for (int j = 0; j < trace1.length; j++) {
                    String line = j + "-->" + trace1[j].toString()
                            + System.getProperty("line.separator");
                    sb1.append(line);
                }
                content.put("cause", sb1.toString());
            } else {
                content.put("cause", "");
            }

            // 7.保存到文件
            String fileName = DateToString(new Date(time),
                    "yyyy-MM-dd HH:mm:ss") + "_" + time + ".txt";

            String dirPath = Environment.getExternalStorageDirectory().getAbsolutePath()
                    + File.separator + "mybaseactivity" + File.separator + "Log";
            File dir = new File(dirPath);
            if (!dir.exists()) {
                dir.mkdirs();
            }

            File file = new File(dirPath, fileName);
            FileOutputStream fos = new FileOutputStream(file);

            BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(
                    fos, "utf-8"));
            bufw.write(content.toString());
            bufw.flush();
            bufw.close();
            fos.close();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }

    /**
     * 保存异常信息到文件中
     *
     * @param e
     * @return
     */
    protected void saveToFile(Throwable e) {

        try {
            long time = System.currentTimeMillis();//获取时间

            /* 文件名格式：andorid_uid_time.txt  //本地文件格式txt*/
            String uid = (String) DLPreferencesUtil.get(mContext,"wangdong","wangdong");//获取用户名字

            //创建文件本地文件名字
            String fileName = "android_" + uid + "_"
                    + DateToString(new Date(time), null)
                    + ".txt";

            String mod = "手机型号:-->" + DLSystemUtil.getModel();
            String mos = "操作系统:-->" + DLSystemUtil.getOs();
            String imei = "IMEI:-->" + DLSystemUtil.getImei(mContext);
            String version = "应用版本:-->" + DLSystemUtil.getAppVersionName(mContext);

            String msg = "原因:-->" + e.toString();
            String date = "时间:-->"
                    + DateToString(new Date(time),
                    null);

            String details = "StackTrace:-------开始------->";
            // 创建盛放异常信息文件的文件夹。。。。/Hair/Log
            String dirPath = Environment.getExternalStorageDirectory().getAbsolutePath()
                    + File.separator + "mybaseactivity" + File.separator + "Log";
            File dir = new File(dirPath);
            if (!dir.exists()) {
                dir.mkdirs();
            }

            File file = new File(dirPath, fileName);
            FileOutputStream fos = new FileOutputStream(file);//输出流

            BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(
                    fos, "utf-8"));
            bufw.write(date);
            bufw.newLine();
            bufw.write(mod);
            bufw.newLine();
            bufw.write(mos);
            bufw.newLine();
            bufw.write(imei);
            bufw.newLine();
            bufw.write(version);
            bufw.newLine();
            bufw.write(msg);
            bufw.newLine();
            bufw.write(details);
            bufw.newLine();

            StackTraceElement[] stackTrace = e.getStackTrace();
            for (int i = 0; i < stackTrace.length; i++) {
                String line = i + "-->" + stackTrace[i].toString();
                bufw.write(line);
                bufw.newLine();
            }
            // bufw.flush();

            String causeInfo = "CauseBy:-------开始------->";
            bufw.write(causeInfo);
            bufw.newLine();

            Throwable cause = e.getCause();
            if (cause != null) {
                StackTraceElement[] trace1 = cause.getStackTrace();
                for (int j = 0; j < trace1.length; j++) {
                    String line = j + "-->" + trace1[j].toString();
                    bufw.write(line);
                    bufw.newLine();
                }
            } else {
                bufw.write("无");
                bufw.newLine();
            }

            bufw.flush();
            bufw.close();
            fos.close();

            upLoadErrorLog(file);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }

    /**
     * 显示提示消息
     */
    public void showMessage(final String msg) {
        new Thread() {
            @Override
            public void run() {
                // Toast 显示需要出现在一个线程的消息队列中
                Looper.prepare();
                Toast.makeText(mContext, "程序出错啦", Toast.LENGTH_LONG).show();
                Looper.loop();
            }
        }.start();
    }

    /**
     * 延时多久关闭应用
     *
     * @param delayTime
     */
    public void closeApplication(long delayTime) {
        // Sleep一会后结束程序，让线程停止一会是为了显示Toast信息给用户，然后Kill程序
        SystemClock.sleep(delayTime);
        XTActivityStack.getInstance().AppExit(mContext);
    }

    /**
     * 上传错误日志
     */
    public void upLoadErrorLog(File... files) {
        //去除中间件
//		uploadLogEngine.execute(files);
//        OkHttpUtils
//                .postFile()
//                .url("")
//                .file(files)
//                .build()
//                .execute(new MyStringCallback());
    }

           /**
            * sd卡是否可用
            *
            * @return
            */
           public  boolean existSDCard() {
               if (android.os.Environment.getExternalStorageState().equals(
                       android.os.Environment.MEDIA_MOUNTED)) {
                   return true;
               } else
                   return false;
           }
           /**
            * 获取imei号
            *
            * @param context
            * @return
            */
           @SuppressLint("MissingPermission")
           public  String getIMEI(Context context) {
               TelephonyManager mTelephonyMgr = (TelephonyManager) context
                       .getSystemService(Context.TELEPHONY_SERVICE);
               return mTelephonyMgr.getDeviceId();
           }
           /**
            * 获取当前应用程序的版本号
            *
            * @return 版本号
            */
           public  String getAppVersion(Context context) {
               // 获取手机的包管理者
               PackageManager pm = context.getPackageManager();
               try {
                   PackageInfo packInfo = pm.getPackageInfo(context.getPackageName(),
                           0);
                   return packInfo.versionName;
               } catch (PackageManager.NameNotFoundException e) {
                   e.printStackTrace();
                   return "";
               }
           }
           /**
            *
            * @param date
            *            string类型的日期 例如:1970-01-01 23:23:23
            * @param format
            *            传入类型的格式 例如:yyyy-MM-dd HH:mm:ss
            * @return
            */
           public static String DateToString(Date date, String format) {
               if (date == null) {
                   return null;
               } else if (TextUtils.isEmpty(format)) {
                   return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
               } else {
                   return new SimpleDateFormat(format).format(date);
               }
           }
}
